Merge "BMC can be configured using different lan channel"
This commit is contained in:
@@ -927,21 +927,38 @@ class GenericHardwareManager(HardwareManager):
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
def get_bmc_address(self):
|
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
|
# These modules are rarely loaded automatically
|
||||||
utils.try_execute('modprobe', 'ipmi_msghandler')
|
utils.try_execute('modprobe', 'ipmi_msghandler')
|
||||||
utils.try_execute('modprobe', 'ipmi_devintf')
|
utils.try_execute('modprobe', 'ipmi_devintf')
|
||||||
utils.try_execute('modprobe', 'ipmi_si')
|
utils.try_execute('modprobe', 'ipmi_si')
|
||||||
|
|
||||||
try:
|
try:
|
||||||
out, _e = utils.execute(
|
# From all the channels 0-15, only 1-7 can be assigned to different
|
||||||
"ipmitool lan print | grep -e 'IP Address [^S]' "
|
# types of communication media and protocols and effectively used
|
||||||
"| awk '{ print $4 }'", shell=True)
|
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:
|
except (processutils.ProcessExecutionError, OSError) as e:
|
||||||
# Not error, because it's normal in virtual environment
|
# Not error, because it's normal in virtual environment
|
||||||
LOG.warning("Cannot get BMC address: %s", e)
|
LOG.warning("Cannot get BMC address: %s", e)
|
||||||
return
|
return
|
||||||
|
|
||||||
return out.strip()
|
return '0.0.0.0'
|
||||||
|
|
||||||
def get_clean_steps(self, node, ports):
|
def get_clean_steps(self, node, ports):
|
||||||
return [
|
return [
|
||||||
|
@@ -1541,6 +1541,40 @@ class TestGenericHardwareManager(base.IronicAgentTest):
|
|||||||
mocked_execute.side_effect = processutils.ProcessExecutionError()
|
mocked_execute.side_effect = processutils.ProcessExecutionError()
|
||||||
self.assertIsNone(self.hardware.get_bmc_address())
|
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)
|
@mock.patch.object(utils, 'execute', autospec=True)
|
||||||
def test_get_system_vendor_info(self, mocked_execute):
|
def test_get_system_vendor_info(self, mocked_execute):
|
||||||
mocked_execute.return_value = (
|
mocked_execute.return_value = (
|
||||||
|
@@ -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.
|
Reference in New Issue
Block a user