summaryrefslogtreecommitdiff
path: root/ironic/tests
diff options
context:
space:
mode:
authorJulia Kreger <juliaashleykreger@gmail.com>2020-10-09 17:12:07 -0700
committerDmitry Tantsur <dtantsur@protonmail.com>2020-12-14 12:00:38 +0000
commita7ac9ce8cd53fdebdf0d9aaeaf439da08a0b3ec8 (patch)
tree646165c509ba7dbea9a545439a3908fc00c0c77a /ironic/tests
parentcde792a8c3b36afd9dd916b38bf60ed6af4f441a (diff)
downloadironic-a7ac9ce8cd53fdebdf0d9aaeaf439da08a0b3ec8.tar.gz
IPMI: Handle vendor set boot device differences
Supermicro machines, when in UEFI mode, have a different device number, in binary, to represent the hard disk from other vendors such as Fujitsu which actually has somewhat similar code in their driver. This means we need to be somewhat cognizent of the vendor of the BMC and possibly update the device mapping based upon that vendor. This may ultimately fix a number of IPMI related problems, because there is a reliance upon the text output of ipmitool, which only reads the bytes retured by the BMC, which may not be reality after the next reset, espescialy if ipmitool doesn't know of the UEFI operating difference. Change-Id: Ie19db9e0cf1eafdfc9bb46248f4d457337821f94 Story: 2008241 Task: 41085
Diffstat (limited to 'ironic/tests')
-rw-r--r--ironic/tests/unit/common/test_neutron.py1
-rw-r--r--ironic/tests/unit/drivers/modules/test_ipmitool.py103
2 files changed, 98 insertions, 6 deletions
diff --git a/ironic/tests/unit/common/test_neutron.py b/ironic/tests/unit/common/test_neutron.py
index 07dcb290e..ec953e927 100644
--- a/ironic/tests/unit/common/test_neutron.py
+++ b/ironic/tests/unit/common/test_neutron.py
@@ -30,6 +30,7 @@ from ironic.tests.unit.db import base as db_base
from ironic.tests.unit.objects import utils as object_utils
from ironic.tests.unit import stubs
+
@mock.patch('ironic.common.keystone.get_service_auth', autospec=True,
return_value=mock.sentinel.sauth)
@mock.patch('ironic.common.keystone.get_auth', autospec=True,
diff --git a/ironic/tests/unit/drivers/modules/test_ipmitool.py b/ironic/tests/unit/drivers/modules/test_ipmitool.py
index 3c7ad07a7..b09dbead6 100644
--- a/ironic/tests/unit/drivers/modules/test_ipmitool.py
+++ b/ironic/tests/unit/drivers/modules/test_ipmitool.py
@@ -58,6 +58,31 @@ INFO_DICT = db_utils.get_test_ipmi_info()
BRIDGE_INFO_DICT = INFO_DICT.copy()
BRIDGE_INFO_DICT.update(db_utils.get_test_ipmi_bridging_parameters())
+MC_INFO = """Device ID : 32
+Device Revision : 1
+Firmware Revision : 0.99
+IPMI Version : 2.0
+Manufacturer ID : 1234
+Manufacturer Name : {vendor}
+Product ID : 2001 (0x0801)
+Product Name : Unknown (0x101)
+Device Available : yes
+Provides Device SDRs : no
+Additional Device Support :
+ Sensor Device
+ SDR Repository Device
+ SEL Device
+ FRU Inventory Device
+ IPMB Event Receiver
+ IPMB Event Generator
+ Chassis Device
+Aux Firmware Rev Info :
+ 0x00
+ 0x00
+ 0x00
+ 0x00
+"""
+
class IPMIToolCheckInitTestCase(base.TestCase):
@@ -1510,20 +1535,22 @@ class IPMIToolPrivateMethodTestCase(
mock.call(self.info, "power status", kill_on_timeout=True)]
with task_manager.acquire(self.context, self.node.uuid) as task:
+ task.node.properties['vendor'] = 'lolcat'
self.assertRaises(exception.PowerStateFailure,
ipmi._power_on, task, self.info, timeout=2)
self.assertEqual(expected, mock_exec.call_args_list)
+ @mock.patch.object(ipmi.IPMIManagement, 'detect_vendor', autospec=True)
@mock.patch.object(ipmi, '_exec_ipmitool', autospec=True)
@mock.patch('oslo_utils.eventletutils.EventletEvent.wait', autospec=True)
- def test__soft_power_off(self, sleep_mock, mock_exec):
-
+ def test__soft_power_off(self, sleep_mock, mock_exec, mock_vendor):
def side_effect(driver_info, command, **kwargs):
resp_dict = {"power status": ["Chassis Power is off\n", None],
"power soft": [None, None]}
return resp_dict.get(command, ["Bad\n", None])
+ mock_vendor.return_value = None
mock_exec.side_effect = side_effect
expected = [mock.call(self.info, "power soft"),
@@ -1534,10 +1561,13 @@ class IPMIToolPrivateMethodTestCase(
self.assertEqual(expected, mock_exec.call_args_list)
self.assertEqual(states.POWER_OFF, state)
+ self.assertTrue(mock_vendor.called)
+ @mock.patch.object(ipmi.IPMIManagement, 'detect_vendor', autospec=True)
@mock.patch.object(ipmi, '_exec_ipmitool', autospec=True)
@mock.patch('oslo_utils.eventletutils.EventletEvent.wait', autospec=True)
- def test__soft_power_off_max_retries(self, sleep_mock, mock_exec):
+ def test__soft_power_off_max_retries(self, sleep_mock, mock_exec,
+ mock_vendor):
def side_effect(driver_info, command, **kwargs):
resp_dict = {"power status": ["Chassis Power is on\n", None],
@@ -1551,10 +1581,13 @@ class IPMIToolPrivateMethodTestCase(
mock.call(self.info, "power status", kill_on_timeout=True)]
with task_manager.acquire(self.context, self.node.uuid) as task:
+ task.node.properties['vendor'] = 'meow5000'
self.assertRaises(exception.PowerStateFailure,
ipmi._soft_power_off, task, self.info, timeout=2)
self.assertEqual(expected, mock_exec.call_args_list)
+ # Should be removed when detect_vendor automatic invocation is moved.
+ self.assertFalse(mock_vendor.called)
@mock.patch.object(ipmi, '_power_status', autospec=True)
@mock.patch.object(ipmi, '_exec_ipmitool', autospec=True)
@@ -1594,8 +1627,9 @@ class IPMIToolDriverTestCase(Base):
self.assertEqual(sorted(expected),
sorted(task.driver.get_properties()))
+ @mock.patch.object(ipmi.IPMIManagement, 'detect_vendor', autospec=True)
@mock.patch.object(ipmi, '_exec_ipmitool', autospec=True)
- def test_get_power_state(self, mock_exec):
+ def test_get_power_state(self, mock_exec, mock_detect):
returns = iter([["Chassis Power is off\n", None],
["Chassis Power is on\n", None],
["\n", None]])
@@ -1603,6 +1637,7 @@ class IPMIToolDriverTestCase(Base):
mock.call(self.info, "power status", kill_on_timeout=True),
mock.call(self.info, "power status", kill_on_timeout=True)]
mock_exec.side_effect = returns
+ mock_detect.return_value = None
with task_manager.acquire(self.context, self.node.uuid) as task:
pstate = self.power.get_power_state(task)
@@ -1615,16 +1650,20 @@ class IPMIToolDriverTestCase(Base):
self.assertEqual(states.ERROR, pstate)
self.assertEqual(mock_exec.call_args_list, expected)
+ self.assertEqual(3, mock_detect.call_count)
+ @mock.patch.object(ipmi.IPMIManagement, 'detect_vendor', autospec=True)
@mock.patch.object(ipmi, '_exec_ipmitool', autospec=True)
- def test_get_power_state_exception(self, mock_exec):
+ def test_get_power_state_exception(self, mock_exec, mock_vendor):
mock_exec.side_effect = processutils.ProcessExecutionError("error")
+ mock_vendor.return_value = None
with task_manager.acquire(self.context, self.node.uuid) as task:
self.assertRaises(exception.IPMIFailure,
self.power.get_power_state,
task)
mock_exec.assert_called_once_with(self.info, "power status",
kill_on_timeout=True)
+ self.assertEqual(1, mock_vendor.call_count)
@mock.patch.object(ipmi, '_power_on', autospec=True)
@mock.patch.object(ipmi, '_power_off', autospec=True)
@@ -2230,7 +2269,7 @@ class IPMIToolDriverTestCase(Base):
mock_calls = [
mock.call(self.info, "raw 0x00 0x08 0x03 0x08"),
- mock.call(self.info, "chassis bootdev pxe options=efiboot")
+ mock.call(self.info, "raw 0x00 0x08 0x05 0xa0 0x04 0x00 0x00 0x00")
]
mock_exec.assert_has_calls(mock_calls)
@@ -2251,6 +2290,48 @@ class IPMIToolDriverTestCase(Base):
]
mock_exec.assert_has_calls(mock_calls)
+ @mock.patch.object(boot_mode_utils, 'get_boot_mode_for_deploy',
+ autospec=True)
+ @mock.patch.object(ipmi, '_exec_ipmitool', autospec=True)
+ def test_management_interface_set_boot_device_uefi_and_persistent_smci(
+ self, mock_exec, mock_boot_mode):
+ mock_boot_mode.return_value = 'uefi'
+ mock_exec.return_value = [None, None]
+ properties = self.node.properties
+ properties['vendor'] = 'SuperMicro'
+ self.node.properties = properties
+ self.node.save()
+ with task_manager.acquire(self.context, self.node.uuid) as task:
+ self.management.set_boot_device(task, boot_devices.DISK,
+ persistent=True)
+ mock_calls = [
+ mock.call(self.info, "raw 0x00 0x08 0x03 0x08"),
+ mock.call(self.info, "raw 0x00 0x08 0x05 0xe0 "
+ "0x24 0x00 0x00 0x00")
+ ]
+ mock_exec.assert_has_calls(mock_calls)
+
+ @mock.patch.object(boot_mode_utils, 'get_boot_mode_for_deploy',
+ autospec=True)
+ @mock.patch.object(ipmi, '_exec_ipmitool', autospec=True)
+ def test_management_interface_set_boot_device_uefi_and_onetime_smci(
+ self, mock_exec, mock_boot_mode):
+ mock_boot_mode.return_value = 'uefi'
+ mock_exec.return_value = [None, None]
+ properties = self.node.properties
+ properties['vendor'] = 'SuperMicro'
+ self.node.properties = properties
+ self.node.save()
+ with task_manager.acquire(self.context, self.node.uuid) as task:
+ self.management.set_boot_device(task, boot_devices.DISK,
+ persistent=False)
+ mock_calls = [
+ mock.call(self.info, "raw 0x00 0x08 0x03 0x08"),
+ mock.call(self.info, "raw 0x00 0x08 0x05 0xa0 "
+ "0x24 0x00 0x00 0x00")
+ ]
+ mock_exec.assert_has_calls(mock_calls)
+
def test_management_interface_get_supported_boot_devices(self):
with task_manager.acquire(self.context, self.node.uuid) as task:
expected = [boot_devices.PXE, boot_devices.DISK,
@@ -2366,6 +2447,16 @@ class IPMIToolDriverTestCase(Base):
mock_exec.assert_called_once_with(driver_info, "power diag")
self.assertTrue(mock_log.called)
+ @mock.patch.object(ipmi, '_exec_ipmitool', autospec=True)
+ def test_detect_vendor(self, mock_exec):
+ mock_exec.return_value = (MC_INFO.format(vendor='LolCatMeow'),
+ None)
+ with task_manager.acquire(self.context, self.node.uuid) as task:
+ driver_info = ipmi._parse_driver_info(task.node)
+ vendor = self.management.detect_vendor(task)
+ mock_exec.assert_called_once_with(driver_info, 'mc info')
+ self.assertEqual('lolcatmeow', vendor)
+
def test__parse_ipmi_sensor_data_ok(self):
fake_sensors_data = """
Sensor ID : Temp (0x1)