summaryrefslogtreecommitdiff
path: root/ironic/drivers/modules
diff options
context:
space:
mode:
authorAlexander Lingo <alingo@nvidia.com>2022-05-06 13:28:02 -0700
committerChris Krelle <ckrelle@nvidia.com>2022-09-09 16:47:47 -0700
commit4415c55028ea9b2bb4b136f5245c3e8059433533 (patch)
tree7116dd35d1555788c676d7bb5ae1b26cee53c7d1 /ironic/drivers/modules
parentb796d7b833f5e8589401418e0c4d967bab7a7d81 (diff)
downloadironic-4415c55028ea9b2bb4b136f5245c3e8059433533.tar.gz
Cleanup submitted SNMP driver code for additional PDUs
* Resolved PEP8 issues * Trimmed comments to remove extraneous information * Changed rfc1902.Integer() calls to the correct snmp.Integer() calls * Fixed power state logic checking for new PDUs that don't have transitional states (e.g., 'pendingOn') * Removed redundant warning messages * Added unit tests for Raritan PD2, ServerTech Sentry 3/4, and Vertiv Geist drivers * Updated documentation to list tested PDUs for the new drivers * Updated release notes Change-Id: I9da7b9042b817c346f75a44cd8287e1f63efcb56
Diffstat (limited to 'ironic/drivers/modules')
-rw-r--r--ironic/drivers/modules/snmp.py339
1 files changed, 339 insertions, 0 deletions
diff --git a/ironic/drivers/modules/snmp.py b/ironic/drivers/modules/snmp.py
index 4e700c6f8..d544d5687 100644
--- a/ironic/drivers/modules/snmp.py
+++ b/ironic/drivers/modules/snmp.py
@@ -799,6 +799,341 @@ class SNMPDriverBaytechMRP27(SNMPDriverSimple):
value_power_on = 1
+class SNMPDriverServerTechSentry3(SNMPDriverBase):
+ """SNMP driver class for Server Technology Sentry 3 PDUs.
+
+ ftp://ftp.servertech.com/Pub/SNMP/sentry3/Sentry3.mib
+
+ SNMP objects for Server Technology Power PDU.
+ 1.3.6.1.4.1.1718.3.2.3.1.5.1.1.<outlet ID> outletStatus
+ Read 0=off, 1=on, 2=off wait, 3=on wait, [...more options follow]
+ 1.3.6.1.4.1.1718.3.2.3.1.11.1.1.<outlet ID> outletControlAction
+ Write 0=no action, 1=on, 2=off, 3=reboot
+ """
+
+ oid_device = (1718, 3, 2, 3, 1)
+ oid_tower_infeed_idx = (1, 1, )
+ oid_power_status = (5,)
+ oid_power_action = (11,)
+
+ status_off = 0
+ status_on = 1
+ status_off_wait = 2
+ status_on_wait = 3
+
+ value_power_on = 1
+ value_power_off = 2
+
+ def __init__(self, *args, **kwargs):
+ super(SNMPDriverServerTechSentry3, self).__init__(*args, **kwargs)
+ # Due to its use of different OIDs for different actions, we only form
+ # an OID that holds the common substring of the OIDs for power
+ # operations.
+ self.oid_base = self.oid_enterprise + self.oid_device
+
+ def _snmp_oid(self, oid):
+ """Return the OID for one of the outlet control objects.
+
+ :param oid: The action-dependent portion of the OID, as a tuple of
+ integers.
+ :returns: The full OID as a tuple of integers.
+ """
+
+ outlet = self.snmp_info['outlet']
+ full_oid = self.oid_base + oid + self.oid_tower_infeed_idx + (outlet,)
+ return full_oid
+
+ def _snmp_power_state(self):
+ oid = self._snmp_oid(self.oid_power_status)
+ state = self.client.get(oid)
+
+ # Translate the state to an Ironic power state.
+ if state in (self.status_on, self.status_off_wait):
+ power_state = states.POWER_ON
+ elif state in (self.status_off, self.status_on_wait):
+ power_state = states.POWER_OFF
+ else:
+ LOG.warning("SeverTech Sentry3 PDU %(addr)s oid %(oid) outlet "
+ "%(outlet)s: unrecognised power state %(state)s.",
+ {'addr': self.snmp_info['address'],
+ 'oid': oid,
+ 'outlet': self.snmp_info['outlet'],
+ 'state': state})
+ power_state = states.ERROR
+
+ return power_state
+
+ def _snmp_power_on(self):
+ oid = self._snmp_oid(self.oid_power_action)
+ value = snmp.Integer(self.value_power_on)
+ self.client.set(oid, value)
+
+ def _snmp_power_off(self):
+ oid = self._snmp_oid(self.oid_power_action)
+ value = snmp.Integer(self.value_power_off)
+ self.client.set(oid, value)
+
+
+class SNMPDriverServerTechSentry4(SNMPDriverBase):
+ """SNMP driver class for Server Technology Sentry 4 PDUs.
+
+ https://www.servertech.com/support/sentry-mib-oid-tree-downloads
+
+ SNMP objects for Server Technology Power PDU.
+ 1.3.6.1.4.1.1718.4.1.8.5.1.1<outlet ID> outletStatus
+ notSet (0) fixedOn (1) idleOff (2) idleOn (3) [...more options follow]
+ pendOn (8) pendOff (9) off (10) on (11) [...more options follow]
+ eventOff (16) eventOn (17) eventReboot (18) eventShutdown (19)
+ 1.3.6.1.4.1.1718.4.1.8.5.1.2.<outlet ID> outletControlAction
+ Write 0=no action, 1=on, 2=off, 3=reboot
+ """
+
+ oid_device = (1718, 4, 1, 8, 5, 1)
+ oid_tower_infeed_idx = (1, 1, )
+ oid_power_status = (1,)
+ oid_power_action = (2,)
+
+ notSet = 0
+ fixedOn = 1
+ idleOff = 2
+ idleOn = 3
+ wakeOff = 4
+ wakeOn = 5
+ ocpOff = 6
+ ocpOn = 7
+ status_pendOn = 8
+ status_pendOff = 9
+ status_off = 10
+ status_on = 11
+ reboot = 12
+ shutdown = 13
+ lockedOff = 14
+ lockedOn = 15
+
+ value_power_on = 1
+ value_power_off = 2
+
+ def __init__(self, *args, **kwargs):
+ super(SNMPDriverServerTechSentry4, self).__init__(*args, **kwargs)
+ # Due to its use of different OIDs for different actions, we only form
+ # an OID that holds the common substring of the OIDs for power
+ # operations.
+ self.oid_base = self.oid_enterprise + self.oid_device
+
+ def _snmp_oid(self, oid):
+ """Return the OID for one of the outlet control objects.
+
+ :param oid: The action-dependent portion of the OID, as a tuple of
+ integers.
+ :returns: The full OID as a tuple of integers.
+ """
+
+ outlet = self.snmp_info['outlet']
+ full_oid = self.oid_base + oid + self.oid_tower_infeed_idx + (outlet,)
+ return full_oid
+
+ def _snmp_power_state(self):
+ oid = self._snmp_oid(self.oid_power_status)
+ state = self.client.get(oid)
+
+ # Translate the state to an Ironic power state.
+ if state in (self.status_on, self.status_pendOn, self.idleOn):
+ power_state = states.POWER_ON
+ elif state in (self.status_off, self.status_pendOff):
+ power_state = states.POWER_OFF
+ else:
+ LOG.warning("ServerTech Sentry4 PDU %(addr)s oid %(oid)s outlet "
+ "%(outlet)s: unrecognised power state %(state)s.",
+ {'addr': self.snmp_info['address'],
+ 'oid': oid,
+ 'outlet': self.snmp_info['outlet'],
+ 'state': state})
+ power_state = states.ERROR
+
+ return power_state
+
+ def _snmp_power_on(self):
+ oid = self._snmp_oid(self.oid_power_action)
+ value = snmp.Integer(self.value_power_on)
+ self.client.set(oid, value)
+
+ def _snmp_power_off(self):
+ oid = self._snmp_oid(self.oid_power_action)
+ value = snmp.Integer(self.value_power_off)
+ self.client.set(oid, value)
+
+
+class SNMPDriverRaritanPDU2(SNMPDriverBase):
+ """SNMP driver class for Raritan PDU2 PDUs.
+
+ http://support.raritan.com/px2/version-2.4.1/mibs/pdu2-mib-020400-39592.txt
+ http://cdn.raritan.com/download/PX/v1.5.20/PDU-MIB.txt
+
+ Command:
+ snmpset -v2c -c private -m+PDU2-MIB <pdu IP address> \
+ PDU2-MIB::switchingOperation.1.4 = cycle
+ snmpset -v2c -c private <pdu IP address> \
+ .1.3.6.1.4.1.13742.6.4.1.2.1.2.1.4 i 2
+ Output:
+ PDU2-MIB::switchingOperation.1.4 = INTEGER: cycle(2)
+ """
+
+ oid_device = (13742, 6, 4, 1, 2, 1)
+ oid_power_action = (2, )
+ oid_power_status = (3, )
+ oid_tower_infeed_idx = (1, )
+
+ unavailable = -1
+ status_open = 0
+ status_closed = 1
+ belowLowerCritical = 2
+ belowLowerWarning = 3
+ status_normal = 4
+ aboveUpperWarning = 5
+ aboveUpperCritical = 6
+ status_on = 7
+ status_off = 8
+ detected = 9
+ notDetected = 10
+ alarmed = 11
+ ok = 12
+ marginal = 13
+ fail = 14
+ yes = 15
+ no = 16
+ standby = 17
+ one = 18
+ two = 19
+ inSync = 20
+ outOfSync = 21
+
+ value_power_on = 1
+ value_power_off = 0
+
+ def __init__(self, *args, **kwargs):
+ super(SNMPDriverRaritanPDU2, self).__init__(*args, **kwargs)
+ # Due to its use of different OIDs for different actions, we only form
+ # an OID that holds the common substring of the OIDs for power
+ # operations.
+ self.oid_base = self.oid_enterprise + self.oid_device
+
+ def _snmp_oid(self, oid):
+ """Return the OID for one of the outlet control objects.
+
+ :param oid: The action-dependent portion of the OID, as a tuple of
+ integers.
+ :returns: The full OID as a tuple of integers.
+ """
+
+ outlet = self.snmp_info['outlet']
+ full_oid = self.oid_base + oid + self.oid_tower_infeed_idx + (outlet,)
+ return full_oid
+
+ def _snmp_power_state(self):
+ oid = self._snmp_oid(self.oid_power_status)
+ state = self.client.get(oid)
+
+ # Translate the state to an Ironic power state.
+ if state == self.status_on:
+ power_state = states.POWER_ON
+ elif state == self.status_off:
+ power_state = states.POWER_OFF
+ else:
+ LOG.warning("Raritan PDU2 PDU %(addr)s oid %(oid)s outlet "
+ "%(outlet)s: unrecognised power state %(state)s.",
+ {'addr': self.snmp_info['address'],
+ 'oid': oid,
+ 'outlet': self.snmp_info['outlet'],
+ 'state': state})
+ power_state = states.ERROR
+
+ return power_state
+
+ def _snmp_power_on(self):
+ oid = self._snmp_oid(self.oid_power_action)
+ value = snmp.Integer(self.value_power_on)
+ self.client.set(oid, value)
+
+ def _snmp_power_off(self):
+ oid = self._snmp_oid(self.oid_power_action)
+ value = snmp.Integer(self.value_power_off)
+ self.client.set(oid, value)
+
+
+class SNMPDriverVertivGeistPDU(SNMPDriverBase):
+ """SNMP driver class for VertivGeist NU30017L/NU30019L PDU.
+
+ https://mibs.observium.org/mib/GEIST-V5-MIB/
+
+ """
+
+ oid_device = (21239, 5, 2, 3, 5, 1)
+ oid_power_action = (6, )
+ oid_power_status = (4, )
+ oid_tower_infeed_idx = (1, )
+
+ on = 1
+ off = 2
+ on2off = 3
+ off2on = 4
+ rebootOn = 5
+ rebootOff = 5
+ unavailable = 7
+
+ value_power_on = 2
+ value_power_off = 4
+
+ def __init__(self, *args, **kwargs):
+ super(SNMPDriverVertivGeistPDU, self).__init__(*args, **kwargs)
+ # Due to its use of different OIDs for different actions, we only form
+ # an OID that holds the common substring of the OIDs for power
+ # operations.
+ self.oid_base = self.oid_enterprise + self.oid_device
+
+ def _snmp_oid(self, oid):
+ """Return the OID for one of the outlet control objects.
+
+ :param oid: The action-dependent portion of the OID, as a tuple of
+ integers.
+
+ :returns: The full OID as a tuple of integers.
+ """
+
+ outlet = self.snmp_info['outlet']
+ full_oid = self.oid_base + oid + (outlet,)
+ return full_oid
+
+ def _snmp_power_state(self):
+ oid = self._snmp_oid(self.oid_power_status)
+ state = self.client.get(oid)
+
+ # Translate the state to an Ironic power state.
+ if state in (self.on, self.on2off):
+ power_state = states.POWER_ON
+ elif state in (self.off, self.off2on):
+ power_state = states.POWER_OFF
+ else:
+ LOG.warning("Vertiv Geist PDU %(addr)s oid %(oid)s outlet "
+ "%(outlet)s: unrecognised power state %(state)s.",
+ {'addr': self.snmp_info['address'],
+ 'oid': oid,
+ 'outlet': self.snmp_info['outlet'],
+ 'state': state})
+ power_state = states.ERROR
+
+ return power_state
+
+ def _snmp_power_on(self):
+ oid = self._snmp_oid(self.oid_power_action)
+ value = snmp.Integer(self.value_power_on)
+ self.client.set(oid, value)
+
+ def _snmp_power_off(self):
+ oid = self._snmp_oid(self.oid_power_action)
+ value = snmp.Integer(self.value_power_off)
+ self.client.set(oid, value)
+
+
class SNMPDriverAuto(SNMPDriverBase):
SYS_OBJ_OID = (1, 3, 6, 1, 2, 1, 1, 2)
@@ -878,6 +1213,10 @@ DRIVER_CLASSES = {
'eatonpower': SNMPDriverEatonPower,
'teltronix': SNMPDriverTeltronix,
'baytech_mrp27': SNMPDriverBaytechMRP27,
+ 'servertech_sentry3': SNMPDriverServerTechSentry3,
+ 'servertech_sentry4': SNMPDriverServerTechSentry4,
+ 'raritan_pdu2': SNMPDriverRaritanPDU2,
+ 'vertivgeist_pdu': SNMPDriverVertivGeistPDU,
'auto': SNMPDriverAuto,
}