Fix OOB introspection to use pxe_enabled flag in idrac driver
Baremetal nodes fail to pxe boot during OpenStack deployment. Reason of this failure is because we are not checking the actual pxe device interface and updating the port pxe_enabled field. This patch make sure that everytime when port is created, it checks the the BIOS and UEFI boot modes of node and fetch the pxe device interfaces values matching to nic id and then update the port's pxe_enabled field. Change-Id: I2890bf16110b713e269d4a4fe410f57273dc8e83 Story: 2004340
This commit is contained in:
parent
e9b4737431
commit
2b74d940c9
@ -119,11 +119,18 @@ class DracInspect(base.InspectInterface):
|
||||
{'node_uuid': node.uuid, 'error': exc})
|
||||
raise exception.HardwareInspectionFailure(error=exc)
|
||||
|
||||
pxe_dev_nics = self._get_pxe_dev_nics(client, nics, node)
|
||||
if pxe_dev_nics is None:
|
||||
LOG.warning('No PXE enabled NIC was found for node '
|
||||
'%(node_uuid)s.', {'node_uuid': node.uuid})
|
||||
|
||||
for nic in nics:
|
||||
try:
|
||||
port = objects.Port(task.context, address=nic.mac,
|
||||
node_id=node.id)
|
||||
node_id=node.id,
|
||||
pxe_enabled=(nic.id in pxe_dev_nics))
|
||||
port.create()
|
||||
|
||||
LOG.info('Port created with MAC address %(mac)s '
|
||||
'for node %(node_uuid)s during inspection',
|
||||
{'mac': nic.mac, 'node_uuid': node.uuid})
|
||||
@ -161,3 +168,47 @@ class DracInspect(base.InspectInterface):
|
||||
return cpu.cores * 2
|
||||
else:
|
||||
return cpu.cores
|
||||
|
||||
def _get_pxe_dev_nics(self, client, nics, node):
|
||||
"""Get a list of pxe device interfaces.
|
||||
|
||||
:param client: Dracclient to list the bios settings and nics
|
||||
:param nics: list of nics
|
||||
|
||||
:returns: Returns list of pxe device interfaces.
|
||||
"""
|
||||
pxe_dev_nics = []
|
||||
pxe_params = ["PxeDev1EnDis", "PxeDev2EnDis",
|
||||
"PxeDev3EnDis", "PxeDev4EnDis"]
|
||||
pxe_nics = ["PxeDev1Interface", "PxeDev2Interface",
|
||||
"PxeDev3Interface", "PxeDev4Interface"]
|
||||
|
||||
try:
|
||||
bios_settings = client.list_bios_settings()
|
||||
except drac_exceptions.BaseClientException as exc:
|
||||
LOG.error('DRAC driver failed to list bios settings '
|
||||
'for %(node_uuid)s. Reason: %(error)s.',
|
||||
{'node_uuid': node.uuid, 'error': exc})
|
||||
raise exception.HardwareInspectionFailure(error=exc)
|
||||
|
||||
if bios_settings["BootMode"].current_value == "Uefi":
|
||||
for param, nic in zip(pxe_params, pxe_nics):
|
||||
if param in bios_settings and bios_settings[
|
||||
param].current_value == "Enabled":
|
||||
pxe_dev_nics.append(
|
||||
bios_settings[nic].current_value)
|
||||
elif bios_settings["BootMode"].current_value == "Bios":
|
||||
for nic in nics:
|
||||
try:
|
||||
nic_cap = client.list_nic_settings(nic_id=nic.id)
|
||||
except drac_exceptions.BaseClientException as exc:
|
||||
LOG.error('DRAC driver failed to list nic settings '
|
||||
'for %(node_uuid)s. Reason: %(error)s.',
|
||||
{'node_uuid': node.uuid, 'error': exc})
|
||||
raise exception.HardwareInspectionFailure(error=exc)
|
||||
|
||||
if ("LegacyBootProto" in nic_cap and nic_cap[
|
||||
'LegacyBootProto'].current_value == "PXE"):
|
||||
pxe_dev_nics.append(nic.id)
|
||||
|
||||
return pxe_dev_nics
|
||||
|
@ -121,6 +121,20 @@ class DracInspectionTestCase(test_utils.BaseDracTest):
|
||||
'speed': '1000 Mbps',
|
||||
'duplex': 'full duplex',
|
||||
'media_type': 'Base T'}]
|
||||
bios_boot_settings = {'BootMode': {'current_value': 'Bios'}}
|
||||
uefi_boot_settings = {'BootMode': {'current_value': 'Uefi'},
|
||||
'PxeDev1EnDis': {'current_value': 'Enabled'},
|
||||
'PxeDev2EnDis': {'current_value': 'Disabled'},
|
||||
'PxeDev3EnDis': {'current_value': 'Disabled'},
|
||||
'PxeDev4EnDis': {'current_value': 'Disabled'},
|
||||
'PxeDev1Interface': {
|
||||
'current_value': 'NIC.Embedded.1-1-1'},
|
||||
'PxeDev2Interface': None,
|
||||
'PxeDev3Interface': None,
|
||||
'PxeDev4Interface': None}
|
||||
nic_settings = {'LegacyBootProto': {'current_value': 'PXE'},
|
||||
'FQDD': 'NIC.Embedded.1-1-1'}
|
||||
|
||||
self.memory = [test_utils.dict_to_namedtuple(values=m) for m in memory]
|
||||
self.cpus = [test_utils.dict_to_namedtuple(values=c) for c in cpus]
|
||||
self.virtual_disks = [test_utils.dict_to_namedtuple(values=vd)
|
||||
@ -128,6 +142,9 @@ class DracInspectionTestCase(test_utils.BaseDracTest):
|
||||
self.physical_disks = [test_utils.dict_to_namedtuple(values=pd)
|
||||
for pd in physical_disks]
|
||||
self.nics = [test_utils.dict_to_namedtuple(values=n) for n in nics]
|
||||
self.bios_boot_settings = test_utils.dict_of_object(bios_boot_settings)
|
||||
self.uefi_boot_settings = test_utils.dict_of_object(uefi_boot_settings)
|
||||
self.nic_settings = test_utils.dict_of_object(nic_settings)
|
||||
|
||||
def test_get_properties(self):
|
||||
expected = drac_common.COMMON_PROPERTIES
|
||||
@ -149,6 +166,7 @@ class DracInspectionTestCase(test_utils.BaseDracTest):
|
||||
mock_client.list_cpus.return_value = self.cpus
|
||||
mock_client.list_virtual_disks.return_value = self.virtual_disks
|
||||
mock_client.list_nics.return_value = self.nics
|
||||
mock_client.list_bios_settings.return_value = self.uefi_boot_settings
|
||||
|
||||
with task_manager.acquire(self.context, self.node.uuid,
|
||||
shared=True) as task:
|
||||
@ -193,6 +211,7 @@ class DracInspectionTestCase(test_utils.BaseDracTest):
|
||||
mock_client.list_virtual_disks.return_value = []
|
||||
mock_client.list_physical_disks.return_value = self.physical_disks
|
||||
mock_client.list_nics.return_value = self.nics
|
||||
mock_client.list_bios_settings.return_value = self.uefi_boot_settings
|
||||
|
||||
with task_manager.acquire(self.context, self.node.uuid,
|
||||
shared=True) as task:
|
||||
@ -237,6 +256,8 @@ class DracInspectionTestCase(test_utils.BaseDracTest):
|
||||
mock_client.list_cpus.return_value = self.cpus
|
||||
mock_client.list_virtual_disks.return_value = self.virtual_disks
|
||||
mock_client.list_nics.return_value = self.nics
|
||||
mock_client.list_bios_settings.return_value = self.uefi_boot_settings
|
||||
|
||||
mock_port_create.side_effect = exception.MACAlreadyExists("boom")
|
||||
|
||||
with task_manager.acquire(self.context, self.node.uuid,
|
||||
@ -271,3 +292,84 @@ class DracInspectionTestCase(test_utils.BaseDracTest):
|
||||
self.cpus[1])
|
||||
|
||||
self.assertEqual(6, cpu)
|
||||
|
||||
@mock.patch.object(drac_common, 'get_drac_client', spec_set=True,
|
||||
autospec=True)
|
||||
def test__get_pxe_dev_nics_with_UEFI_boot_mode(self, mock_get_drac_client):
|
||||
expected_pxe_nic = self.uefi_boot_settings[
|
||||
'PxeDev1Interface'].current_value
|
||||
mock_client = mock.Mock()
|
||||
mock_get_drac_client.return_value = mock_client
|
||||
mock_client.list_bios_settings.return_value = self.uefi_boot_settings
|
||||
with task_manager.acquire(self.context, self.node.uuid,
|
||||
shared=True) as task:
|
||||
pxe_dev_nics = task.driver.inspect._get_pxe_dev_nics(
|
||||
mock_client, self.nics, self.node)
|
||||
|
||||
self.assertEqual(expected_pxe_nic, pxe_dev_nics[0])
|
||||
|
||||
@mock.patch.object(drac_common, 'get_drac_client', spec_set=True,
|
||||
autospec=True)
|
||||
def test__get_pxe_dev_nics_with_BIOS_boot_mode(self, mock_get_drac_client):
|
||||
expected_pxe_nic = self.nic_settings['FQDD']
|
||||
mock_client = mock.Mock()
|
||||
mock_get_drac_client.return_value = mock_client
|
||||
mock_client.list_bios_settings.return_value = self.bios_boot_settings
|
||||
mock_client.list_nic_settings.return_value = self.nic_settings
|
||||
with task_manager.acquire(self.context, self.node.uuid,
|
||||
shared=True) as task:
|
||||
pxe_dev_nics = task.driver.inspect._get_pxe_dev_nics(
|
||||
mock_client, self.nics, self.node)
|
||||
|
||||
self.assertEqual(expected_pxe_nic, pxe_dev_nics[0])
|
||||
|
||||
@mock.patch.object(drac_common, 'get_drac_client', spec_set=True,
|
||||
autospec=True)
|
||||
def test__get_pxe_dev_nics_list_boot_setting_failure(self,
|
||||
mock_get_drac_client):
|
||||
mock_client = mock.Mock()
|
||||
mock_get_drac_client.return_value = mock_client
|
||||
mock_client.list_bios_settings.side_effect = (
|
||||
drac_exceptions.BaseClientException('foo'))
|
||||
|
||||
with task_manager.acquire(self.context, self.node.uuid,
|
||||
shared=True) as task:
|
||||
self.assertRaises(exception.HardwareInspectionFailure,
|
||||
task.driver.inspect._get_pxe_dev_nics,
|
||||
mock_client,
|
||||
self.nics,
|
||||
self.node)
|
||||
|
||||
@mock.patch.object(drac_common, 'get_drac_client', spec_set=True,
|
||||
autospec=True)
|
||||
def test__get_pxe_dev_nics_list_nic_setting_failure(self,
|
||||
mock_get_drac_client):
|
||||
mock_client = mock.Mock()
|
||||
mock_get_drac_client.return_value = mock_client
|
||||
mock_client.list_bios_settings.return_value = self.bios_boot_settings
|
||||
mock_client.list_nic_settings.side_effect = (
|
||||
drac_exceptions.BaseClientException('bar'))
|
||||
|
||||
with task_manager.acquire(self.context, self.node.uuid,
|
||||
shared=True) as task:
|
||||
self.assertRaises(exception.HardwareInspectionFailure,
|
||||
task.driver.inspect._get_pxe_dev_nics,
|
||||
mock_client,
|
||||
self.nics,
|
||||
self.node)
|
||||
|
||||
@mock.patch.object(drac_common, 'get_drac_client', spec_set=True,
|
||||
autospec=True)
|
||||
def test__get_pxe_dev_nics_with_empty_list(self, mock_get_drac_client):
|
||||
expected_pxe_nic = []
|
||||
nic_setting = []
|
||||
mock_client = mock.Mock()
|
||||
mock_get_drac_client.return_value = mock_client
|
||||
mock_client.list_bios_settings.return_value = self.bios_boot_settings
|
||||
mock_client.list_nic_settings.return_value = nic_setting
|
||||
with task_manager.acquire(self.context, self.node.uuid,
|
||||
shared=True) as task:
|
||||
pxe_dev_nics = task.driver.inspect._get_pxe_dev_nics(
|
||||
mock_client, self.nics, self.node)
|
||||
|
||||
self.assertEqual(expected_pxe_nic, pxe_dev_nics)
|
||||
|
@ -31,6 +31,13 @@ class BaseDracTest(db_base.DbTestCase):
|
||||
enabled_raid_interfaces=['idrac', 'fake', 'no-raid'])
|
||||
|
||||
|
||||
class DictToObj(object):
|
||||
"""Returns a dictionary into a class"""
|
||||
def __init__(self, dictionary):
|
||||
for key in dictionary:
|
||||
setattr(self, key, dictionary[key])
|
||||
|
||||
|
||||
def dict_to_namedtuple(name='GenericNamedTuple', values=None):
|
||||
"""Converts a dict to a collections.namedtuple"""
|
||||
|
||||
@ -38,3 +45,13 @@ def dict_to_namedtuple(name='GenericNamedTuple', values=None):
|
||||
values = {}
|
||||
|
||||
return collections.namedtuple(name, list(values))(**values)
|
||||
|
||||
|
||||
def dict_of_object(data):
|
||||
"""Create a dictionary object"""
|
||||
|
||||
for k, v in data.items():
|
||||
if isinstance(v, dict):
|
||||
dict_obj = DictToObj(v)
|
||||
data[k] = dict_obj
|
||||
return data
|
||||
|
@ -0,0 +1,7 @@
|
||||
---
|
||||
fixes:
|
||||
- |
|
||||
Fixes a bug where ironic port is not updated in node introspection as per
|
||||
PXE enabled setting for ``idrac`` hardware type.
|
||||
See bug `2004340
|
||||
<https://storyboard.openstack.org/#!/story/2004340>`_ for details.
|
Loading…
Reference in New Issue
Block a user