summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordigambar <digambarpatil15@yahoo.co.in>2018-11-27 04:17:02 -0500
committerDigambar <digambarpatil15@yahoo.co.in>2018-12-11 05:04:43 +0000
commit828ec3ee397eb96427927ecd5f57d6f1c23a4af2 (patch)
tree6774e163a1ad57fb2dac4961ec469d0f83cda49c
parent6a6c0d882fe8ac299d18df75d2bbd111b170ad48 (diff)
downloadironic-828ec3ee397eb96427927ecd5f57d6f1c23a4af2.tar.gz
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 (cherry picked from commit 2b74d940c932c1bb4498f47372c0545e4480799f)
-rw-r--r--ironic/drivers/modules/drac/inspect.py53
-rw-r--r--ironic/tests/unit/drivers/modules/drac/test_inspect.py102
-rw-r--r--ironic/tests/unit/drivers/modules/drac/utils.py17
-rw-r--r--releasenotes/notes/update-port-pxe-enabled-f954f934209cbf5b.yaml7
4 files changed, 178 insertions, 1 deletions
diff --git a/ironic/drivers/modules/drac/inspect.py b/ironic/drivers/modules/drac/inspect.py
index bdccfd018..b452da6b0 100644
--- a/ironic/drivers/modules/drac/inspect.py
+++ b/ironic/drivers/modules/drac/inspect.py
@@ -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
diff --git a/ironic/tests/unit/drivers/modules/drac/test_inspect.py b/ironic/tests/unit/drivers/modules/drac/test_inspect.py
index 1d650e29f..9ab83939f 100644
--- a/ironic/tests/unit/drivers/modules/drac/test_inspect.py
+++ b/ironic/tests/unit/drivers/modules/drac/test_inspect.py
@@ -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)
diff --git a/ironic/tests/unit/drivers/modules/drac/utils.py b/ironic/tests/unit/drivers/modules/drac/utils.py
index 4884a2cd0..319c4f050 100644
--- a/ironic/tests/unit/drivers/modules/drac/utils.py
+++ b/ironic/tests/unit/drivers/modules/drac/utils.py
@@ -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
diff --git a/releasenotes/notes/update-port-pxe-enabled-f954f934209cbf5b.yaml b/releasenotes/notes/update-port-pxe-enabled-f954f934209cbf5b.yaml
new file mode 100644
index 000000000..1e0bfa1d1
--- /dev/null
+++ b/releasenotes/notes/update-port-pxe-enabled-f954f934209cbf5b.yaml
@@ -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.