Merge "Migrate ironic snmp
driver to the latest pysnmp API"
This commit is contained in:
commit
157739435e
@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
# These are available on pypi
|
# These are available on pypi
|
||||||
proliantutils>=2.5.0
|
proliantutils>=2.5.0
|
||||||
pysnmp
|
pysnmp>=4.3.0,<5.0.0
|
||||||
python-ironic-inspector-client>=1.5.0
|
python-ironic-inspector-client>=1.5.0
|
||||||
python-oneviewclient<3.0.0,>=2.5.2
|
python-oneviewclient<3.0.0,>=2.5.2
|
||||||
python-scciclient>=0.7.1
|
python-scciclient>=0.7.1
|
||||||
|
@ -41,24 +41,23 @@ from ironic.drivers import base
|
|||||||
|
|
||||||
pysnmp = importutils.try_import('pysnmp')
|
pysnmp = importutils.try_import('pysnmp')
|
||||||
if pysnmp:
|
if pysnmp:
|
||||||
from pysnmp.entity.rfc3413.oneliner import cmdgen
|
|
||||||
from pysnmp import error as snmp_error
|
from pysnmp import error as snmp_error
|
||||||
from pysnmp.proto import rfc1902
|
from pysnmp import hlapi as snmp
|
||||||
|
|
||||||
snmp_auth_protocols = {
|
snmp_auth_protocols = {
|
||||||
'md5': cmdgen.usmHMACMD5AuthProtocol,
|
'md5': snmp.usmHMACMD5AuthProtocol,
|
||||||
'sha': cmdgen.usmHMACSHAAuthProtocol,
|
'sha': snmp.usmHMACSHAAuthProtocol,
|
||||||
'none': cmdgen.usmNoAuthProtocol,
|
'none': snmp.usmNoAuthProtocol,
|
||||||
}
|
}
|
||||||
|
|
||||||
# available since pysnmp 4.4.1
|
# available since pysnmp 4.4.1
|
||||||
try:
|
try:
|
||||||
snmp_auth_protocols.update(
|
snmp_auth_protocols.update(
|
||||||
{
|
{
|
||||||
'sha224': cmdgen.usmHMAC128SHA224AuthProtocol,
|
'sha224': snmp.usmHMAC128SHA224AuthProtocol,
|
||||||
'sha256': cmdgen.usmHMAC192SHA256AuthProtocol,
|
'sha256': snmp.usmHMAC192SHA256AuthProtocol,
|
||||||
'sha384': cmdgen.usmHMAC256SHA384AuthProtocol,
|
'sha384': snmp.usmHMAC256SHA384AuthProtocol,
|
||||||
'sha512': cmdgen.usmHMAC384SHA512AuthProtocol,
|
'sha512': snmp.usmHMAC384SHA512AuthProtocol,
|
||||||
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@ -67,20 +66,20 @@ if pysnmp:
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
snmp_priv_protocols = {
|
snmp_priv_protocols = {
|
||||||
'des': cmdgen.usmDESPrivProtocol,
|
'des': snmp.usmDESPrivProtocol,
|
||||||
'3des': cmdgen.usm3DESEDEPrivProtocol,
|
'3des': snmp.usm3DESEDEPrivProtocol,
|
||||||
'aes': cmdgen.usmAesCfb128Protocol,
|
'aes': snmp.usmAesCfb128Protocol,
|
||||||
'aes192': cmdgen.usmAesCfb192Protocol,
|
'aes192': snmp.usmAesCfb192Protocol,
|
||||||
'aes256': cmdgen.usmAesCfb256Protocol,
|
'aes256': snmp.usmAesCfb256Protocol,
|
||||||
'none': cmdgen.usmNoPrivProtocol,
|
'none': snmp.usmNoPrivProtocol,
|
||||||
}
|
}
|
||||||
|
|
||||||
# available since pysnmp 4.4.3
|
# available since pysnmp 4.4.3
|
||||||
try:
|
try:
|
||||||
snmp_priv_protocols.update(
|
snmp_priv_protocols.update(
|
||||||
{
|
{
|
||||||
'aes192blmt': cmdgen.usmAesBlumenthalCfb192Protocol,
|
'aes192blmt': snmp.usmAesBlumenthalCfb192Protocol,
|
||||||
'aes256blmt': cmdgen.usmAesBlumenthalCfb256Protocol,
|
'aes256blmt': snmp.usmAesBlumenthalCfb256Protocol,
|
||||||
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@ -89,9 +88,8 @@ if pysnmp:
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
else:
|
else:
|
||||||
cmdgen = None
|
snmp = None
|
||||||
snmp_error = None
|
snmp_error = None
|
||||||
rfc1902 = None
|
|
||||||
|
|
||||||
snmp_auth_protocols = {
|
snmp_auth_protocols = {
|
||||||
'none': None
|
'none': None
|
||||||
@ -198,7 +196,7 @@ class SNMPClient(object):
|
|||||||
user=None, auth_proto=None,
|
user=None, auth_proto=None,
|
||||||
auth_key=None, priv_proto=None,
|
auth_key=None, priv_proto=None,
|
||||||
priv_key=None, context_engine_id=None, context_name=None):
|
priv_key=None, context_engine_id=None, context_name=None):
|
||||||
if not cmdgen:
|
if not snmp:
|
||||||
raise exception.DriverLoadError(
|
raise exception.DriverLoadError(
|
||||||
driver=self.__class__.__name__,
|
driver=self.__class__.__name__,
|
||||||
reason=_("Unable to import python-pysnmp library")
|
reason=_("Unable to import python-pysnmp library")
|
||||||
@ -213,13 +211,14 @@ class SNMPClient(object):
|
|||||||
self.auth_key = auth_key
|
self.auth_key = auth_key
|
||||||
self.priv_proto = priv_proto
|
self.priv_proto = priv_proto
|
||||||
self.priv_key = priv_key
|
self.priv_key = priv_key
|
||||||
self.context_engine_id = context_engine_id
|
|
||||||
self.context_name = context_name or ''
|
|
||||||
else:
|
else:
|
||||||
self.read_community = read_community
|
self.read_community = read_community
|
||||||
self.write_community = write_community
|
self.write_community = write_community
|
||||||
|
|
||||||
self.cmd_gen = cmdgen.CommandGenerator()
|
self.context_engine_id = context_engine_id
|
||||||
|
self.context_name = context_name or ''
|
||||||
|
|
||||||
|
self.snmp_engine = snmp.SnmpEngine()
|
||||||
|
|
||||||
def _get_auth(self, write_mode=False):
|
def _get_auth(self, write_mode=False):
|
||||||
"""Return the authorization data for an SNMP request.
|
"""Return the authorization data for an SNMP request.
|
||||||
@ -227,23 +226,22 @@ class SNMPClient(object):
|
|||||||
:param write_mode: `True` if write class SNMP command is
|
:param write_mode: `True` if write class SNMP command is
|
||||||
executed. Default is `False`.
|
executed. Default is `False`.
|
||||||
:returns: Either
|
:returns: Either
|
||||||
:class:`pysnmp.entity.rfc3413.oneliner.cmdgen.CommunityData`
|
:class:`pysnmp.hlapi.CommunityData`
|
||||||
or :class:`pysnmp.entity.rfc3413.oneliner.cmdgen.UsmUserData`
|
or :class:`pysnmp.hlapi.UsmUserData`
|
||||||
object depending on SNMP version being used.
|
object depending on SNMP version being used.
|
||||||
"""
|
"""
|
||||||
if self.version == SNMP_V3:
|
if self.version == SNMP_V3:
|
||||||
return cmdgen.UsmUserData(
|
return snmp.UsmUserData(
|
||||||
self.user,
|
self.user,
|
||||||
authKey=self.auth_key,
|
authKey=self.auth_key,
|
||||||
authProtocol=self.auth_proto,
|
authProtocol=self.auth_proto,
|
||||||
privKey=self.priv_key,
|
privKey=self.priv_key,
|
||||||
privProtocol=self.priv_proto,
|
privProtocol=self.priv_proto
|
||||||
contextEngineId=self.context_engine_id,
|
|
||||||
contextName=self.context_name
|
|
||||||
)
|
)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
mp_model = 1 if self.version == SNMP_V2C else 0
|
mp_model = 1 if self.version == SNMP_V2C else 0
|
||||||
return cmdgen.CommunityData(
|
return snmp.CommunityData(
|
||||||
self.write_community if write_mode else self.read_community,
|
self.write_community if write_mode else self.read_community,
|
||||||
mpModel=mp_model
|
mpModel=mp_model
|
||||||
)
|
)
|
||||||
@ -252,17 +250,31 @@ class SNMPClient(object):
|
|||||||
"""Return the transport target for an SNMP request.
|
"""Return the transport target for an SNMP request.
|
||||||
|
|
||||||
:returns: A :class:
|
:returns: A :class:
|
||||||
`pysnmp.entity.rfc3413.oneliner.cmdgen.UdpTransportTarget` object.
|
`pysnmp.hlapi.UdpTransportTarget` object.
|
||||||
:raises: snmp_error.PySnmpError if the transport address is bad.
|
:raises: :class:`pysnmp.error.PySnmpError` if the transport address
|
||||||
|
is bad.
|
||||||
"""
|
"""
|
||||||
# The transport target accepts timeout and retries parameters, which
|
# The transport target accepts timeout and retries parameters, which
|
||||||
# default to 1 (second) and 5 respectively. These are deemed sensible
|
# default to 1 (second) and 5 respectively. These are deemed sensible
|
||||||
# enough to allow for an unreliable network or slow device.
|
# enough to allow for an unreliable network or slow device.
|
||||||
return cmdgen.UdpTransportTarget(
|
return snmp.UdpTransportTarget(
|
||||||
(self.address, self.port),
|
(self.address, self.port),
|
||||||
timeout=CONF.snmp.udp_transport_timeout,
|
timeout=CONF.snmp.udp_transport_timeout,
|
||||||
retries=CONF.snmp.udp_transport_retries)
|
retries=CONF.snmp.udp_transport_retries)
|
||||||
|
|
||||||
|
def _get_context(self):
|
||||||
|
"""Return the SNMP context for an SNMP request.
|
||||||
|
|
||||||
|
:returns: A :class:
|
||||||
|
`pysnmp.hlapi.ContextData` object.
|
||||||
|
:raises: :class:`pysnmp.error.PySnmpError` if SNMP context data
|
||||||
|
is bad.
|
||||||
|
"""
|
||||||
|
return snmp.ContextData(
|
||||||
|
contextEngineId=self.context_engine_id,
|
||||||
|
contextName=self.context_name
|
||||||
|
)
|
||||||
|
|
||||||
def get(self, oid):
|
def get(self, oid):
|
||||||
"""Use PySNMP to perform an SNMP GET operation on a single object.
|
"""Use PySNMP to perform an SNMP GET operation on a single object.
|
||||||
|
|
||||||
@ -271,13 +283,16 @@ class SNMPClient(object):
|
|||||||
:returns: The value of the requested object.
|
:returns: The value of the requested object.
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
results = self.cmd_gen.getCmd(self._get_auth(),
|
snmp_gen = snmp.getCmd(self.snmp_engine,
|
||||||
self._get_transport(),
|
self._get_auth(),
|
||||||
oid)
|
self._get_transport(),
|
||||||
|
self._get_context(),
|
||||||
|
snmp.ObjectType(snmp.ObjectIdentity(oid)))
|
||||||
|
|
||||||
except snmp_error.PySnmpError as e:
|
except snmp_error.PySnmpError as e:
|
||||||
raise exception.SNMPFailure(operation="GET", error=e)
|
raise exception.SNMPFailure(operation="GET", error=e)
|
||||||
|
|
||||||
error_indication, error_status, error_index, var_binds = results
|
error_indication, error_status, error_index, var_binds = next(snmp_gen)
|
||||||
|
|
||||||
if error_indication:
|
if error_indication:
|
||||||
# SNMP engine-level error.
|
# SNMP engine-level error.
|
||||||
@ -301,13 +316,17 @@ class SNMPClient(object):
|
|||||||
:returns: A list of values of the requested table object.
|
:returns: A list of values of the requested table object.
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
results = self.cmd_gen.nextCmd(self._get_auth(),
|
snmp_gen = snmp.nextCmd(self.snmp_engine,
|
||||||
self._get_transport(),
|
self._get_auth(),
|
||||||
oid)
|
self._get_transport(),
|
||||||
|
self._get_context(),
|
||||||
|
snmp.ObjectType(snmp.ObjectIdentity(oid)))
|
||||||
|
|
||||||
except snmp_error.PySnmpError as e:
|
except snmp_error.PySnmpError as e:
|
||||||
raise exception.SNMPFailure(operation="GET_NEXT", error=e)
|
raise exception.SNMPFailure(operation="GET_NEXT", error=e)
|
||||||
|
|
||||||
error_indication, error_status, error_index, var_bind_table = results
|
(error_indication, error_status, error_index,
|
||||||
|
var_bind_table) = next(snmp_gen)
|
||||||
|
|
||||||
if error_indication:
|
if error_indication:
|
||||||
# SNMP engine-level error.
|
# SNMP engine-level error.
|
||||||
@ -329,13 +348,17 @@ class SNMPClient(object):
|
|||||||
:raises: SNMPFailure if an SNMP request fails.
|
:raises: SNMPFailure if an SNMP request fails.
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
results = self.cmd_gen.setCmd(self._get_auth(write_mode=True),
|
snmp_gen = snmp.setCmd(self.snmp_engine,
|
||||||
self._get_transport(),
|
self._get_auth(write_mode=True),
|
||||||
(oid, value))
|
self._get_transport(),
|
||||||
|
self._get_context(),
|
||||||
|
snmp.ObjectType(
|
||||||
|
snmp.ObjectIdentity(oid), value))
|
||||||
|
|
||||||
except snmp_error.PySnmpError as e:
|
except snmp_error.PySnmpError as e:
|
||||||
raise exception.SNMPFailure(operation="SET", error=e)
|
raise exception.SNMPFailure(operation="SET", error=e)
|
||||||
|
|
||||||
error_indication, error_status, error_index, var_binds = results
|
error_indication, error_status, error_index, var_binds = next(snmp_gen)
|
||||||
|
|
||||||
if error_indication:
|
if error_indication:
|
||||||
# SNMP engine-level error.
|
# SNMP engine-level error.
|
||||||
@ -565,11 +588,11 @@ class SNMPDriverSimple(SNMPDriverBase):
|
|||||||
return power_state
|
return power_state
|
||||||
|
|
||||||
def _snmp_power_on(self):
|
def _snmp_power_on(self):
|
||||||
value = rfc1902.Integer(self.value_power_on)
|
value = snmp.Integer(self.value_power_on)
|
||||||
self.client.set(self.oid, value)
|
self.client.set(self.oid, value)
|
||||||
|
|
||||||
def _snmp_power_off(self):
|
def _snmp_power_off(self):
|
||||||
value = rfc1902.Integer(self.value_power_off)
|
value = snmp.Integer(self.value_power_off)
|
||||||
self.client.set(self.oid, value)
|
self.client.set(self.oid, value)
|
||||||
|
|
||||||
|
|
||||||
@ -739,12 +762,12 @@ class SNMPDriverEatonPower(SNMPDriverBase):
|
|||||||
|
|
||||||
def _snmp_power_on(self):
|
def _snmp_power_on(self):
|
||||||
oid = self._snmp_oid(self.oid_poweron)
|
oid = self._snmp_oid(self.oid_poweron)
|
||||||
value = rfc1902.Integer(self.value_power_on)
|
value = snmp.Integer(self.value_power_on)
|
||||||
self.client.set(oid, value)
|
self.client.set(oid, value)
|
||||||
|
|
||||||
def _snmp_power_off(self):
|
def _snmp_power_off(self):
|
||||||
oid = self._snmp_oid(self.oid_poweroff)
|
oid = self._snmp_oid(self.oid_poweroff)
|
||||||
value = rfc1902.Integer(self.value_power_off)
|
value = snmp.Integer(self.value_power_off)
|
||||||
self.client.set(oid, value)
|
self.client.set(oid, value)
|
||||||
|
|
||||||
|
|
||||||
|
@ -20,8 +20,8 @@ import time
|
|||||||
|
|
||||||
import mock
|
import mock
|
||||||
from oslo_config import cfg
|
from oslo_config import cfg
|
||||||
from pysnmp.entity.rfc3413.oneliner import cmdgen
|
|
||||||
from pysnmp import error as snmp_error
|
from pysnmp import error as snmp_error
|
||||||
|
from pysnmp import hlapi as pysnmp
|
||||||
|
|
||||||
from ironic.common import exception
|
from ironic.common import exception
|
||||||
from ironic.common import states
|
from ironic.common import states
|
||||||
@ -37,210 +37,218 @@ CONF = cfg.CONF
|
|||||||
INFO_DICT = db_utils.get_test_snmp_info()
|
INFO_DICT = db_utils.get_test_snmp_info()
|
||||||
|
|
||||||
|
|
||||||
@mock.patch.object(cmdgen, 'CommandGenerator', autospec=True)
|
|
||||||
class SNMPClientTestCase(base.TestCase):
|
class SNMPClientTestCase(base.TestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
super(SNMPClientTestCase, self).setUp()
|
super(SNMPClientTestCase, self).setUp()
|
||||||
self.address = '1.2.3.4'
|
self.address = '1.2.3.4'
|
||||||
self.port = '6700'
|
self.port = '6700'
|
||||||
self.oid = 'oid'
|
self.oid = (1, 3, 6, 1, 1, 1, 0)
|
||||||
self.value = 'value'
|
self.value = 'value'
|
||||||
|
|
||||||
def test___init__(self, mock_cmdgen):
|
@mock.patch.object(pysnmp, 'SnmpEngine', autospec=True)
|
||||||
|
def test___init__(self, mock_snmpengine):
|
||||||
client = snmp.SNMPClient(self.address, self.port, snmp.SNMP_V1)
|
client = snmp.SNMPClient(self.address, self.port, snmp.SNMP_V1)
|
||||||
mock_cmdgen.assert_called_once_with()
|
mock_snmpengine.assert_called_once_with()
|
||||||
self.assertEqual(self.address, client.address)
|
self.assertEqual(self.address, client.address)
|
||||||
self.assertEqual(self.port, client.port)
|
self.assertEqual(self.port, client.port)
|
||||||
self.assertEqual(snmp.SNMP_V1, client.version)
|
self.assertEqual(snmp.SNMP_V1, client.version)
|
||||||
self.assertIsNone(client.read_community)
|
self.assertIsNone(client.read_community)
|
||||||
self.assertIsNone(client.write_community)
|
self.assertIsNone(client.write_community)
|
||||||
self.assertNotIn('user', client.__dict__)
|
self.assertNotIn('user', client.__dict__)
|
||||||
self.assertEqual(mock_cmdgen.return_value, client.cmd_gen)
|
self.assertEqual(mock_snmpengine.return_value, client.snmp_engine)
|
||||||
|
|
||||||
@mock.patch.object(cmdgen, 'CommunityData', autospec=True)
|
@mock.patch.object(pysnmp, 'CommunityData', autospec=True)
|
||||||
def test__get_auth_v1_read(self, mock_community, mock_cmdgen):
|
def test__get_auth_v1_read(self, mock_community):
|
||||||
client = snmp.SNMPClient(self.address, self.port, snmp.SNMP_V1,
|
client = snmp.SNMPClient(self.address, self.port, snmp.SNMP_V1,
|
||||||
read_community='public',
|
read_community='public',
|
||||||
write_community='private')
|
write_community='private')
|
||||||
client._get_auth()
|
client._get_auth()
|
||||||
mock_cmdgen.assert_called_once_with()
|
|
||||||
mock_community.assert_called_once_with(client.read_community,
|
mock_community.assert_called_once_with(client.read_community,
|
||||||
mpModel=0)
|
mpModel=0)
|
||||||
|
|
||||||
@mock.patch.object(cmdgen, 'CommunityData', autospec=True)
|
@mock.patch.object(pysnmp, 'CommunityData', autospec=True)
|
||||||
def test__get_auth_v1_write(self, mock_community, mock_cmdgen):
|
def test__get_auth_v1_write(self, mock_community):
|
||||||
client = snmp.SNMPClient(self.address, self.port, snmp.SNMP_V1,
|
client = snmp.SNMPClient(self.address, self.port, snmp.SNMP_V1,
|
||||||
read_community='public',
|
read_community='public',
|
||||||
write_community='private')
|
write_community='private')
|
||||||
client._get_auth(write_mode=True)
|
client._get_auth(write_mode=True)
|
||||||
mock_cmdgen.assert_called_once_with()
|
|
||||||
mock_community.assert_called_once_with(client.write_community,
|
mock_community.assert_called_once_with(client.write_community,
|
||||||
mpModel=0)
|
mpModel=0)
|
||||||
|
|
||||||
@mock.patch.object(cmdgen, 'UsmUserData', autospec=True)
|
@mock.patch.object(pysnmp, 'UsmUserData', autospec=True)
|
||||||
def test__get_auth_v3(self, mock_user, mock_cmdgen):
|
def test__get_auth_v3(self, mock_user):
|
||||||
client = snmp.SNMPClient(self.address, self.port, snmp.SNMP_V3)
|
client = snmp.SNMPClient(self.address, self.port, snmp.SNMP_V3)
|
||||||
client._get_auth()
|
client._get_auth()
|
||||||
mock_cmdgen.assert_called_once_with()
|
|
||||||
mock_user.assert_called_once_with(
|
mock_user.assert_called_once_with(
|
||||||
client.user,
|
client.user,
|
||||||
authKey=client.auth_key,
|
authKey=client.auth_key,
|
||||||
authProtocol=client.auth_proto,
|
authProtocol=client.auth_proto,
|
||||||
privKey=client.priv_key,
|
privKey=client.priv_key,
|
||||||
privProtocol=client.priv_proto,
|
privProtocol=client.priv_proto,
|
||||||
contextEngineId=client.context_engine_id,
|
|
||||||
contextName=client.context_name
|
|
||||||
)
|
)
|
||||||
|
|
||||||
@mock.patch.object(cmdgen, 'UdpTransportTarget', autospec=True)
|
@mock.patch.object(pysnmp, 'ContextData', autospec=True)
|
||||||
def test__get_transport(self, mock_transport, mock_cmdgen):
|
def test__get_context(self, mock_context):
|
||||||
|
client = snmp.SNMPClient(self.address, self.port, snmp.SNMP_V1)
|
||||||
|
client._get_context()
|
||||||
|
mock_context.assert_called_once_with(None, '')
|
||||||
|
|
||||||
|
@mock.patch.object(pysnmp, 'UdpTransportTarget', autospec=True)
|
||||||
|
def test__get_transport(self, mock_transport):
|
||||||
client = snmp.SNMPClient(self.address, self.port, snmp.SNMP_V3)
|
client = snmp.SNMPClient(self.address, self.port, snmp.SNMP_V3)
|
||||||
client._get_transport()
|
client._get_transport()
|
||||||
mock_cmdgen.assert_called_once_with()
|
|
||||||
mock_transport.assert_called_once_with(
|
mock_transport.assert_called_once_with(
|
||||||
(client.address, client.port),
|
(client.address, client.port),
|
||||||
retries=CONF.snmp.udp_transport_retries,
|
retries=CONF.snmp.udp_transport_retries,
|
||||||
timeout=CONF.snmp.udp_transport_timeout)
|
timeout=CONF.snmp.udp_transport_timeout)
|
||||||
|
|
||||||
@mock.patch.object(cmdgen, 'UdpTransportTarget', autospec=True)
|
@mock.patch.object(pysnmp, 'UdpTransportTarget', autospec=True)
|
||||||
def test__get_transport_err(self, mock_transport, mock_cmdgen):
|
def test__get_transport_err(self, mock_transport):
|
||||||
mock_transport.side_effect = snmp_error.PySnmpError
|
mock_transport.side_effect = snmp_error.PySnmpError
|
||||||
client = snmp.SNMPClient(self.address, self.port, snmp.SNMP_V3)
|
client = snmp.SNMPClient(self.address, self.port, snmp.SNMP_V3)
|
||||||
self.assertRaises(snmp_error.PySnmpError, client._get_transport)
|
self.assertRaises(snmp_error.PySnmpError, client._get_transport)
|
||||||
mock_cmdgen.assert_called_once_with()
|
|
||||||
mock_transport.assert_called_once_with(
|
mock_transport.assert_called_once_with(
|
||||||
(client.address, client.port),
|
(client.address, client.port),
|
||||||
retries=CONF.snmp.udp_transport_retries,
|
retries=CONF.snmp.udp_transport_retries,
|
||||||
timeout=CONF.snmp.udp_transport_timeout)
|
timeout=CONF.snmp.udp_transport_timeout)
|
||||||
|
|
||||||
@mock.patch.object(cmdgen, 'UdpTransportTarget', autospec=True)
|
@mock.patch.object(pysnmp, 'UdpTransportTarget', autospec=True)
|
||||||
def test__get_transport_custom_timeout(self, mock_transport, mock_cmdgen):
|
def test__get_transport_custom_timeout(self, mock_transport):
|
||||||
self.config(udp_transport_timeout=2.0, group='snmp')
|
self.config(udp_transport_timeout=2.0, group='snmp')
|
||||||
client = snmp.SNMPClient(self.address, self.port, snmp.SNMP_V3)
|
client = snmp.SNMPClient(self.address, self.port, snmp.SNMP_V3)
|
||||||
client._get_transport()
|
client._get_transport()
|
||||||
mock_cmdgen.assert_called_once_with()
|
|
||||||
mock_transport.assert_called_once_with((client.address, client.port),
|
mock_transport.assert_called_once_with((client.address, client.port),
|
||||||
retries=5, timeout=2.0)
|
retries=5, timeout=2.0)
|
||||||
|
|
||||||
@mock.patch.object(cmdgen, 'UdpTransportTarget', autospec=True)
|
@mock.patch.object(pysnmp, 'UdpTransportTarget', autospec=True)
|
||||||
def test__get_transport_custom_retries(self, mock_transport, mock_cmdgen):
|
def test__get_transport_custom_retries(self, mock_transport):
|
||||||
self.config(udp_transport_retries=10, group='snmp')
|
self.config(udp_transport_retries=10, group='snmp')
|
||||||
client = snmp.SNMPClient(self.address, self.port, snmp.SNMP_V3)
|
client = snmp.SNMPClient(self.address, self.port, snmp.SNMP_V3)
|
||||||
client._get_transport()
|
client._get_transport()
|
||||||
mock_cmdgen.assert_called_once_with()
|
|
||||||
mock_transport.assert_called_once_with((client.address, client.port),
|
mock_transport.assert_called_once_with((client.address, client.port),
|
||||||
retries=10, timeout=1.0)
|
retries=10, timeout=1.0)
|
||||||
|
|
||||||
|
@mock.patch.object(pysnmp, 'getCmd', autospec=True)
|
||||||
@mock.patch.object(snmp.SNMPClient, '_get_transport', autospec=True)
|
@mock.patch.object(snmp.SNMPClient, '_get_transport', autospec=True)
|
||||||
|
@mock.patch.object(snmp.SNMPClient, '_get_context', autospec=True)
|
||||||
@mock.patch.object(snmp.SNMPClient, '_get_auth', autospec=True)
|
@mock.patch.object(snmp.SNMPClient, '_get_auth', autospec=True)
|
||||||
def test_get(self, mock_auth, mock_transport, mock_cmdgen):
|
def test_get(self, mock_auth, mock_context, mock_transport, mock_getcmd):
|
||||||
var_bind = (self.oid, self.value)
|
var_bind = (self.oid, self.value)
|
||||||
mock_cmdgenerator = mock_cmdgen.return_value
|
mock_getcmd.return_value = iter([("", None, 0, [var_bind])])
|
||||||
mock_cmdgenerator.getCmd.return_value = ("", None, 0, [var_bind])
|
|
||||||
client = snmp.SNMPClient(self.address, self.port, snmp.SNMP_V3)
|
client = snmp.SNMPClient(self.address, self.port, snmp.SNMP_V3)
|
||||||
val = client.get(self.oid)
|
val = client.get(self.oid)
|
||||||
self.assertEqual(var_bind[1], val)
|
self.assertEqual(var_bind[1], val)
|
||||||
mock_cmdgenerator.getCmd.assert_called_once_with(mock.ANY, mock.ANY,
|
self.assertEqual(1, mock_getcmd.call_count)
|
||||||
self.oid)
|
|
||||||
|
|
||||||
|
@mock.patch.object(pysnmp, 'nextCmd', autospec=True)
|
||||||
@mock.patch.object(snmp.SNMPClient, '_get_transport', autospec=True)
|
@mock.patch.object(snmp.SNMPClient, '_get_transport', autospec=True)
|
||||||
|
@mock.patch.object(snmp.SNMPClient, '_get_context', autospec=True)
|
||||||
@mock.patch.object(snmp.SNMPClient, '_get_auth', autospec=True)
|
@mock.patch.object(snmp.SNMPClient, '_get_auth', autospec=True)
|
||||||
def test_get_next(self, mock_auth, mock_transport, mock_cmdgen):
|
def test_get_next(self, mock_auth, mock_context, mock_transport,
|
||||||
|
mock_nextcmd):
|
||||||
var_bind = (self.oid, self.value)
|
var_bind = (self.oid, self.value)
|
||||||
mock_cmdgenerator = mock_cmdgen.return_value
|
mock_nextcmd.return_value = iter([("", None, 0,
|
||||||
mock_cmdgenerator.nextCmd.return_value = (
|
[[var_bind, var_bind]])])
|
||||||
"", None, 0, [[var_bind, var_bind]])
|
|
||||||
client = snmp.SNMPClient(self.address, self.port, snmp.SNMP_V3)
|
client = snmp.SNMPClient(self.address, self.port, snmp.SNMP_V3)
|
||||||
val = client.get_next(self.oid)
|
val = client.get_next(self.oid)
|
||||||
self.assertEqual([self.value, self.value], val)
|
self.assertEqual([self.value, self.value], val)
|
||||||
mock_cmdgenerator.nextCmd.assert_called_once_with(mock.ANY, mock.ANY,
|
self.assertEqual(1, mock_nextcmd.call_count)
|
||||||
self.oid)
|
|
||||||
|
|
||||||
|
@mock.patch.object(pysnmp, 'getCmd', autospec=True)
|
||||||
@mock.patch.object(snmp.SNMPClient, '_get_transport', autospec=True)
|
@mock.patch.object(snmp.SNMPClient, '_get_transport', autospec=True)
|
||||||
|
@mock.patch.object(snmp.SNMPClient, '_get_context', autospec=True)
|
||||||
@mock.patch.object(snmp.SNMPClient, '_get_auth', autospec=True)
|
@mock.patch.object(snmp.SNMPClient, '_get_auth', autospec=True)
|
||||||
def test_get_err_transport(self, mock_auth, mock_transport, mock_cmdgen):
|
def test_get_err_transport(self, mock_auth, mock_context, mock_transport,
|
||||||
|
mock_getcmd):
|
||||||
mock_transport.side_effect = snmp_error.PySnmpError
|
mock_transport.side_effect = snmp_error.PySnmpError
|
||||||
var_bind = (self.oid, self.value)
|
var_bind = (self.oid, self.value)
|
||||||
mock_cmdgenerator = mock_cmdgen.return_value
|
mock_getcmd.return_value = iter([("engine error", None,
|
||||||
mock_cmdgenerator.getCmd.return_value = ("engine error", None, 0,
|
0, [var_bind])])
|
||||||
[var_bind])
|
|
||||||
client = snmp.SNMPClient(self.address, self.port, snmp.SNMP_V3)
|
client = snmp.SNMPClient(self.address, self.port, snmp.SNMP_V3)
|
||||||
self.assertRaises(exception.SNMPFailure, client.get, self.oid)
|
self.assertRaises(exception.SNMPFailure, client.get, self.oid)
|
||||||
self.assertFalse(mock_cmdgenerator.getCmd.called)
|
self.assertFalse(mock_getcmd.called)
|
||||||
|
|
||||||
|
@mock.patch.object(pysnmp, 'nextCmd', autospec=True)
|
||||||
@mock.patch.object(snmp.SNMPClient, '_get_transport', autospec=True)
|
@mock.patch.object(snmp.SNMPClient, '_get_transport', autospec=True)
|
||||||
|
@mock.patch.object(snmp.SNMPClient, '_get_context', autospec=True)
|
||||||
@mock.patch.object(snmp.SNMPClient, '_get_auth', autospec=True)
|
@mock.patch.object(snmp.SNMPClient, '_get_auth', autospec=True)
|
||||||
def test_get_next_err_transport(self, mock_auth, mock_transport,
|
def test_get_next_err_transport(self, mock_auth, mock_context,
|
||||||
mock_cmdgen):
|
mock_transport, mock_nextcmd):
|
||||||
mock_transport.side_effect = snmp_error.PySnmpError
|
mock_transport.side_effect = snmp_error.PySnmpError
|
||||||
var_bind = (self.oid, self.value)
|
var_bind = (self.oid, self.value)
|
||||||
mock_cmdgenerator = mock_cmdgen.return_value
|
mock_nextcmd.return_value = iter([("engine error", None, 0,
|
||||||
mock_cmdgenerator.nextCmd.return_value = ("engine error", None, 0,
|
[var_bind])])
|
||||||
[[var_bind, var_bind]])
|
|
||||||
client = snmp.SNMPClient(self.address, self.port, snmp.SNMP_V3)
|
client = snmp.SNMPClient(self.address, self.port, snmp.SNMP_V3)
|
||||||
self.assertRaises(exception.SNMPFailure, client.get_next, self.oid)
|
self.assertRaises(exception.SNMPFailure, client.get_next, self.oid)
|
||||||
self.assertFalse(mock_cmdgenerator.nextCmd.called)
|
self.assertFalse(mock_nextcmd.called)
|
||||||
|
|
||||||
|
@mock.patch.object(pysnmp, 'getCmd', autospec=True)
|
||||||
@mock.patch.object(snmp.SNMPClient, '_get_transport', autospec=True)
|
@mock.patch.object(snmp.SNMPClient, '_get_transport', autospec=True)
|
||||||
|
@mock.patch.object(snmp.SNMPClient, '_get_context', autospec=True)
|
||||||
@mock.patch.object(snmp.SNMPClient, '_get_auth', autospec=True)
|
@mock.patch.object(snmp.SNMPClient, '_get_auth', autospec=True)
|
||||||
def test_get_err_engine(self, mock_auth, mock_transport, mock_cmdgen):
|
def test_get_err_engine(self, mock_auth, mock_context, mock_transport,
|
||||||
|
mock_getcmd):
|
||||||
var_bind = (self.oid, self.value)
|
var_bind = (self.oid, self.value)
|
||||||
mock_cmdgenerator = mock_cmdgen.return_value
|
mock_getcmd.return_value = iter([("engine error", None, 0,
|
||||||
mock_cmdgenerator.getCmd.return_value = ("engine error", None, 0,
|
[var_bind])])
|
||||||
[var_bind])
|
|
||||||
client = snmp.SNMPClient(self.address, self.port, snmp.SNMP_V3)
|
client = snmp.SNMPClient(self.address, self.port, snmp.SNMP_V3)
|
||||||
self.assertRaises(exception.SNMPFailure, client.get, self.oid)
|
self.assertRaises(exception.SNMPFailure, client.get, self.oid)
|
||||||
mock_cmdgenerator.getCmd.assert_called_once_with(mock.ANY, mock.ANY,
|
self.assertEqual(1, mock_getcmd.call_count)
|
||||||
self.oid)
|
|
||||||
|
|
||||||
|
@mock.patch.object(pysnmp, 'nextCmd', autospec=True)
|
||||||
@mock.patch.object(snmp.SNMPClient, '_get_transport', autospec=True)
|
@mock.patch.object(snmp.SNMPClient, '_get_transport', autospec=True)
|
||||||
|
@mock.patch.object(snmp.SNMPClient, '_get_context', autospec=True)
|
||||||
@mock.patch.object(snmp.SNMPClient, '_get_auth', autospec=True)
|
@mock.patch.object(snmp.SNMPClient, '_get_auth', autospec=True)
|
||||||
def test_get_next_err_engine(self, mock_auth, mock_transport, mock_cmdgen):
|
def test_get_next_err_engine(self, mock_auth, mock_context,
|
||||||
|
mock_transport, mock_nextcmd):
|
||||||
var_bind = (self.oid, self.value)
|
var_bind = (self.oid, self.value)
|
||||||
mock_cmdgenerator = mock_cmdgen.return_value
|
mock_nextcmd.return_value = iter([("engine error", None, 0,
|
||||||
mock_cmdgenerator.nextCmd.return_value = ("engine error", None, 0,
|
[var_bind])])
|
||||||
[[var_bind, var_bind]])
|
|
||||||
client = snmp.SNMPClient(self.address, self.port, snmp.SNMP_V3)
|
client = snmp.SNMPClient(self.address, self.port, snmp.SNMP_V3)
|
||||||
self.assertRaises(exception.SNMPFailure, client.get_next, self.oid)
|
self.assertRaises(exception.SNMPFailure, client.get_next, self.oid)
|
||||||
mock_cmdgenerator.nextCmd.assert_called_once_with(mock.ANY, mock.ANY,
|
self.assertEqual(1, mock_nextcmd.call_count)
|
||||||
self.oid)
|
|
||||||
|
|
||||||
|
@mock.patch.object(pysnmp, 'setCmd', autospec=True)
|
||||||
@mock.patch.object(snmp.SNMPClient, '_get_transport', autospec=True)
|
@mock.patch.object(snmp.SNMPClient, '_get_transport', autospec=True)
|
||||||
|
@mock.patch.object(snmp.SNMPClient, '_get_context', autospec=True)
|
||||||
@mock.patch.object(snmp.SNMPClient, '_get_auth', autospec=True)
|
@mock.patch.object(snmp.SNMPClient, '_get_auth', autospec=True)
|
||||||
def test_set(self, mock_auth, mock_transport, mock_cmdgen):
|
def test_set(self, mock_auth, mock_context, mock_transport,
|
||||||
|
mock_setcmd):
|
||||||
var_bind = (self.oid, self.value)
|
var_bind = (self.oid, self.value)
|
||||||
mock_cmdgenerator = mock_cmdgen.return_value
|
mock_setcmd.return_value = iter([("", None, 0,
|
||||||
mock_cmdgenerator.setCmd.return_value = ("", None, 0, [var_bind])
|
[var_bind])])
|
||||||
client = snmp.SNMPClient(self.address, self.port, snmp.SNMP_V3)
|
client = snmp.SNMPClient(self.address, self.port, snmp.SNMP_V3)
|
||||||
client.set(self.oid, self.value)
|
client.set(self.oid, self.value)
|
||||||
mock_cmdgenerator.setCmd.assert_called_once_with(mock.ANY, mock.ANY,
|
self.assertEqual(1, mock_setcmd.call_count)
|
||||||
var_bind)
|
|
||||||
|
|
||||||
|
@mock.patch.object(pysnmp, 'setCmd', autospec=True)
|
||||||
@mock.patch.object(snmp.SNMPClient, '_get_transport', autospec=True)
|
@mock.patch.object(snmp.SNMPClient, '_get_transport', autospec=True)
|
||||||
|
@mock.patch.object(snmp.SNMPClient, '_get_context', autospec=True)
|
||||||
@mock.patch.object(snmp.SNMPClient, '_get_auth', autospec=True)
|
@mock.patch.object(snmp.SNMPClient, '_get_auth', autospec=True)
|
||||||
def test_set_err_transport(self, mock_auth, mock_transport, mock_cmdgen):
|
def test_set_err_transport(self, mock_auth, mock_context, mock_transport,
|
||||||
|
mock_setcmd):
|
||||||
mock_transport.side_effect = snmp_error.PySnmpError
|
mock_transport.side_effect = snmp_error.PySnmpError
|
||||||
var_bind = (self.oid, self.value)
|
var_bind = (self.oid, self.value)
|
||||||
mock_cmdgenerator = mock_cmdgen.return_value
|
mock_setcmd.return_value = iter([("engine error", None, 0,
|
||||||
mock_cmdgenerator.setCmd.return_value = ("engine error", None, 0,
|
[var_bind])])
|
||||||
[var_bind])
|
|
||||||
client = snmp.SNMPClient(self.address, self.port, snmp.SNMP_V3)
|
client = snmp.SNMPClient(self.address, self.port, snmp.SNMP_V3)
|
||||||
self.assertRaises(exception.SNMPFailure,
|
self.assertRaises(exception.SNMPFailure, client.set, self.oid,
|
||||||
client.set, self.oid, self.value)
|
self.value)
|
||||||
self.assertFalse(mock_cmdgenerator.setCmd.called)
|
self.assertFalse(mock_setcmd.called)
|
||||||
|
|
||||||
|
@mock.patch.object(pysnmp, 'setCmd', autospec=True)
|
||||||
@mock.patch.object(snmp.SNMPClient, '_get_transport', autospec=True)
|
@mock.patch.object(snmp.SNMPClient, '_get_transport', autospec=True)
|
||||||
|
@mock.patch.object(snmp.SNMPClient, '_get_context', autospec=True)
|
||||||
@mock.patch.object(snmp.SNMPClient, '_get_auth', autospec=True)
|
@mock.patch.object(snmp.SNMPClient, '_get_auth', autospec=True)
|
||||||
def test_set_err_engine(self, mock_auth, mock_transport, mock_cmdgen):
|
def test_set_err_engine(self, mock_auth, mock_context, mock_transport,
|
||||||
|
mock_setcmd):
|
||||||
var_bind = (self.oid, self.value)
|
var_bind = (self.oid, self.value)
|
||||||
mock_cmdgenerator = mock_cmdgen.return_value
|
mock_setcmd.return_value = iter([("engine error", None, 0,
|
||||||
mock_cmdgenerator.setCmd.return_value = ("engine error", None, 0,
|
[var_bind])])
|
||||||
[var_bind])
|
|
||||||
client = snmp.SNMPClient(self.address, self.port, snmp.SNMP_V3)
|
client = snmp.SNMPClient(self.address, self.port, snmp.SNMP_V3)
|
||||||
self.assertRaises(exception.SNMPFailure,
|
self.assertRaises(exception.SNMPFailure, client.set, self.oid,
|
||||||
client.set, self.oid, self.value)
|
self.value)
|
||||||
mock_cmdgenerator.setCmd.assert_called_once_with(mock.ANY, mock.ANY,
|
self.assertEqual(1, mock_setcmd.call_count)
|
||||||
var_bind)
|
|
||||||
|
|
||||||
|
|
||||||
class SNMPValidateParametersTestCase(db_base.DbTestCase):
|
class SNMPValidateParametersTestCase(db_base.DbTestCase):
|
||||||
|
@ -71,9 +71,8 @@ PYWSMAN_SPEC = (
|
|||||||
|
|
||||||
# pywsnmp
|
# pywsnmp
|
||||||
PYWSNMP_SPEC = (
|
PYWSNMP_SPEC = (
|
||||||
'entity',
|
'hlapi',
|
||||||
'error',
|
'error',
|
||||||
'proto',
|
|
||||||
)
|
)
|
||||||
|
|
||||||
# scciclient
|
# scciclient
|
||||||
|
@ -117,24 +117,18 @@ if not dracclient:
|
|||||||
if 'ironic.drivers.modules.drac' in sys.modules:
|
if 'ironic.drivers.modules.drac' in sys.modules:
|
||||||
six.moves.reload_module(sys.modules['ironic.drivers.modules.drac'])
|
six.moves.reload_module(sys.modules['ironic.drivers.modules.drac'])
|
||||||
|
|
||||||
|
|
||||||
# attempt to load the external 'pysnmp' library, which is required by
|
# attempt to load the external 'pysnmp' library, which is required by
|
||||||
# the optional drivers.modules.snmp module
|
# the optional drivers.modules.snmp module
|
||||||
pysnmp = importutils.try_import("pysnmp")
|
pysnmp = importutils.try_import("pysnmp")
|
||||||
if not pysnmp:
|
if not pysnmp:
|
||||||
pysnmp = mock.MagicMock(spec_set=mock_specs.PYWSNMP_SPEC)
|
pysnmp = mock.MagicMock(spec_set=mock_specs.PYWSNMP_SPEC)
|
||||||
sys.modules["pysnmp"] = pysnmp
|
sys.modules["pysnmp"] = pysnmp
|
||||||
sys.modules["pysnmp.entity"] = pysnmp.entity
|
sys.modules["pysnmp.hlapi"] = pysnmp.hlapi
|
||||||
sys.modules["pysnmp.entity.rfc3413"] = pysnmp.entity.rfc3413
|
|
||||||
sys.modules["pysnmp.entity.rfc3413.oneliner"] = (
|
|
||||||
pysnmp.entity.rfc3413.oneliner)
|
|
||||||
sys.modules["pysnmp.entity.rfc3413.oneliner.cmdgen"] = (
|
|
||||||
pysnmp.entity.rfc3413.oneliner.cmdgen)
|
|
||||||
sys.modules["pysnmp.error"] = pysnmp.error
|
sys.modules["pysnmp.error"] = pysnmp.error
|
||||||
pysnmp.error.PySnmpError = Exception
|
pysnmp.error.PySnmpError = Exception
|
||||||
sys.modules["pysnmp.proto"] = pysnmp.proto
|
|
||||||
sys.modules["pysnmp.proto.rfc1902"] = pysnmp.proto.rfc1902
|
|
||||||
# Patch the RFC1902 integer class with a python int
|
# Patch the RFC1902 integer class with a python int
|
||||||
pysnmp.proto.rfc1902.Integer = int
|
pysnmp.hlapi.Integer = int
|
||||||
|
|
||||||
|
|
||||||
# if anything has loaded the snmp driver yet, reload it now that the
|
# if anything has loaded the snmp driver yet, reload it now that the
|
||||||
|
@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
upgrade:
|
||||||
|
- The minimum required version of pysnmp has been bumped to 4.3. This
|
||||||
|
pysnmp version introduces simpler, faster and more functional high-level
|
||||||
|
SNMP API on which ironic `snmp` driver has been migrated.
|
Loading…
x
Reference in New Issue
Block a user