Merge "BMC can be configured using different lan channel"

This commit is contained in:
Jenkins 2017-08-10 09:39:55 +00:00 committed by Gerrit Code Review
commit a487120187
3 changed files with 62 additions and 4 deletions

View File

@ -927,21 +927,38 @@ class GenericHardwareManager(HardwareManager):
return True
def get_bmc_address(self):
"""Attempt to detect BMC IP address
:return: IP address of lan channel or 0.0.0.0 in case none of them is
configured properly
"""
# These modules are rarely loaded automatically
utils.try_execute('modprobe', 'ipmi_msghandler')
utils.try_execute('modprobe', 'ipmi_devintf')
utils.try_execute('modprobe', 'ipmi_si')
try:
out, _e = utils.execute(
"ipmitool lan print | grep -e 'IP Address [^S]' "
"| awk '{ print $4 }'", shell=True)
# From all the channels 0-15, only 1-7 can be assigned to different
# types of communication media and protocols and effectively used
for channel in range(1, 8):
out, e = utils.execute(
"ipmitool lan print {} | awk '/IP Address[[:space:]]*:/"
" {{print $4}}'".format(channel), shell=True)
# Invalid channel cannot be followed by a valid one, so we can
# safely break here
if e.startswith("Invalid channel"):
break
# In case we get empty IP or 0.0.0.0 on a valid channel,
# we need to keep querying
if out.strip() not in ('', '0.0.0.0'):
return out.strip()
except (processutils.ProcessExecutionError, OSError) as e:
# Not error, because it's normal in virtual environment
LOG.warning("Cannot get BMC address: %s", e)
return
return out.strip()
return '0.0.0.0'
def get_clean_steps(self, node, ports):
return [

View File

@ -1541,6 +1541,40 @@ class TestGenericHardwareManager(base.IronicAgentTest):
mocked_execute.side_effect = processutils.ProcessExecutionError()
self.assertIsNone(self.hardware.get_bmc_address())
@mock.patch.object(utils, 'execute', autospec=True)
def test_get_bmc_address_zeroed(self, mocked_execute):
mocked_execute.return_value = '0.0.0.0\n', ''
self.assertEqual('0.0.0.0', self.hardware.get_bmc_address())
@mock.patch.object(utils, 'execute', autospec=True)
def test_get_bmc_address_invalid(self, mocked_execute):
# In case of invalid lan channel, stdout is empty and the error
# on stderr is "Invalid channel"
mocked_execute.return_value = '\n', 'Invalid channel: 55'
self.assertEqual('0.0.0.0', self.hardware.get_bmc_address())
@mock.patch.object(utils, 'execute', autospec=True)
def test_get_bmc_address_random_error(self, mocked_execute):
mocked_execute.return_value = '192.1.2.3\n', 'Random error message'
self.assertEqual('192.1.2.3', self.hardware.get_bmc_address())
@mock.patch.object(utils, 'execute', autospec=True)
def test_get_bmc_address_iterate_channels(self, mocked_execute):
# For channel 1 we simulate unconfigured IP
# and for any other we return a correct IP address
def side_effect(*args, **kwargs):
if args[0].startswith("ipmitool lan print 1"):
return '0.0.0.0\n', ''
else:
return '192.1.2.3\n', ''
mocked_execute.side_effect = side_effect
self.assertEqual('192.1.2.3', self.hardware.get_bmc_address())
@mock.patch.object(utils, 'execute', autospec=True)
def test_get_bmc_address_not_available(self, mocked_execute):
mocked_execute.return_value = '', ''
self.assertEqual('0.0.0.0', self.hardware.get_bmc_address())
@mock.patch.object(utils, 'execute', autospec=True)
def test_get_system_vendor_info(self, mocked_execute):
mocked_execute.return_value = (

View File

@ -0,0 +1,7 @@
---
fixes:
- |
IPMI interface can be configured to use lan channel different than
a default one. In that case querying it will return 0.0.0.0 as an IP
address representing an interface lacking configuration. In order to get
the real IP address, we need to iterate through all the possible channels.